/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package l1j.server.server.model;

import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.map.L1Map;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_Teleport;
import l1j.server.server.utils.Teleportation;
import static l1j.server.server.model.skill.L1SkillId.TELEPORT_DELAY;

public class L1Teleport {

	// テレポートスキルの種類
	public static final int TELEPORT = 0;

	public static final int CHANGE_POSITION = 1;

	public static final int ADVANCED_MASS_TELEPORT = 2;

	public static final int CALL_CLAN = 3;

	// 順番にteleport(白), change position e(青), ad mass teleport e(赤), call clan(緑)
	public static final int[] EFFECT_SPR = { 169, 2235, 2236, 2281 };

	public static final int[] EFFECT_TIME = { 280, 440, 440, 1120 };

	private static final Logger _log = Logger.getLogger(L1Teleport.class.getName());


	/**
	 * 隨機執行移動
	 * @param pc
	 * @param effectable
	 */
	public static void randomTeleport(final L1PcInstance pc, final boolean effectable) {
		try {
			// まだ本サーバのランテレ処理と違うところが結構あるような・・・
			final L1Location newLocation = pc.getLocation().randomLocation(200, true);
			final int newX = newLocation.getX();
			final int newY = newLocation.getY();
			final short mapId = (short) newLocation.getMapId();

			L1Teleport.teleport(pc, newX, newY, mapId, pc.getHeading(), effectable);

		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage() , e);
		}
	}

	/**
	 * 傳送控制項
	 * @param pc 執行的人物
	 * @param x X座標
	 * @param y Y座標
	 * @param mapId 地圖編號
	 * @param head 面向
	 * @param effectable 是否產生動畫
	 */
	public static void teleport(final L1PcInstance pc, final int x, final int y, final short mapid,final int head, final boolean effectable) {
		teleport(pc, x, y, mapid, head, effectable, TELEPORT);
	}
	/**
	 * 傳送控制項(傳送術、集體傳送術、世界樹的呼喚)
	 * @param pc 執行的人物
	 * @param x X座標
	 * @param y Y座標
	 * @param mapId 地圖編號
	 * @param head 面向
	 * @param effectable 是否產生動畫
	 */
	public static void teleportByMagic(final L1PcInstance pc, final int x, final int y, final short mapid,final int head, final boolean effectable) {
		teleportMagic(pc, x, y, mapid, head, effectable, TELEPORT);
	}
	/**
	 * 傳送控制項(傳送術、集體傳送術、世界樹的呼喚)
	 * @param pc 執行的人物
	 * @param x X座標
	 * @param y Y座標
	 * @param mapId 地圖編號
	 * @param head 面向
	 * @param effectable 是否產生動畫
	 * @param skillType 動畫的光 (0:白),(1:青),(2:赤),(3:緑)
	 */
	public static void teleportMagic(final L1PcInstance pc, final int x, final int y, final short mapId,
			final int head, final boolean effectable, final int skillType) {

		if(pc.isTeleport()){
			return;
		}
		if(pc.isPrivateShop()){
			return;
		}
		if(pc.isDead()){
			return;
		}
		pc.setTeleport(true);
		// 保存寵物目前模式
		//				pc.setPetModel();
		// 傳送鎖定解除
		//pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK, false));
		// 瞬移, 取消交易
		if (pc.getTradeID() != 0) {
			final L1Trade trade = new L1Trade();
			trade.TradeCancel(pc);
		}
		// 動畫顯示
		if (effectable && skillType >= 0 && skillType <= EFFECT_SPR.length) {
			final S_SkillSound packet = new S_SkillSound(pc.getId(), EFFECT_SPR[skillType]);
			pc.sendPacketsAll(packet);

			// テレポート以外のsprはキャラが消えないので見た目上送っておきたいが
			// 移動中だった場合クラ落ちすることがある
			// if (skillType != TELEPORT) {
			// pc.sendPackets(new S_DeleteNewObject(pc));
			// pc.broadcastPacket(new S_DeleteObjectFromScreen(pc));
			// }

			try {
				Thread.sleep((int) (EFFECT_TIME[skillType] * 0.7));
			}catch (final Exception e) {
			}
		}
		pc.setTeleportX(x);
		pc.setTeleportY(y);
		pc.setTeleportMapId(mapId);
		pc.setTeleportHeading(head);
		//		if (Config.SEND_PACKET_BEFORE_TELEPORT) {
		//			pc.sendPackets(new S_Teleport(pc));
		//
		//		}else {
		//		pc.sendPackets(new S_Teleport(pc));
		Teleportation.actionTeleportation(pc);
		//		}
	}
	/**
	 * 傳送控制項
	 * @param pc 執行的人物
	 * @param x X座標
	 * @param y Y座標
	 * @param mapId 地圖編號
	 * @param head 面向
	 * @param effectable 是否產生動畫
	 * @param skillType 動畫的光 (0:白),(1:青),(2:赤),(3:緑)
	 */
	public static void teleport(final L1PcInstance pc, final int x, final int y, final short mapId,
			final int head, final boolean effectable, final int skillType) {

		if(pc.isTeleport()){
			return;
		}
		if(pc.isPrivateShop()){
			return;
		}
		if(pc.isDead()){
			return;
		}
		pc.setTeleport(true);
		// 保存寵物目前模式
		//				pc.setPetModel();
		// 傳送鎖定解除
		//pc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_TELEPORT_UNLOCK, false));
		// 瞬移, 取消交易
		if (pc.getTradeID() != 0) {
			final L1Trade trade = new L1Trade();
			trade.TradeCancel(pc);
		}
		// 動畫顯示
		if (effectable && skillType >= 0 && skillType <= EFFECT_SPR.length) {
			pc.sendPacketsAll(new S_SkillSound(pc.getId(), EFFECT_SPR[skillType]));

			// テレポート以外のsprはキャラが消えないので見た目上送っておきたいが
			// 移動中だった場合クラ落ちすることがある
			// if (skillType != TELEPORT) {
			// pc.sendPackets(new S_DeleteNewObject(pc));
			// pc.broadcastPacket(new S_DeleteObjectFromScreen(pc));
			// }

			try {
				Thread.sleep((int) (EFFECT_TIME[skillType] * 0.7));
			}catch (final Exception e) {
			}
		}

		pc.setTeleportX(x);
		pc.setTeleportY(y);
		pc.setTeleportMapId(mapId);
		pc.setTeleportHeading(head);
		//		if (Config.SEND_PACKET_BEFORE_TELEPORT) {
		//			pc.sendPackets(new S_Teleport(pc));
		//
		//		}else {
		pc.setSkillEffect(TELEPORT_DELAY, 5000);
		pc.sendPackets(new S_Teleport(pc.getId()));
		//			Teleportation.actionTeleportation(pc);
		//		}
	}

	/**
	 * 傳送控制項
	 * @param pc 執行的人物
	 * @param loc 座標
	 * @param head 面向
	 * @param effectable 是否產生動畫
	 */
	public static void teleport(final L1PcInstance pc, final L1Location loc, final int head,final boolean effectable) {

		teleport(pc, loc.getX(), loc.getY(), (short) loc.getMapId(), head,effectable, TELEPORT);
	}

	/**
	 * 傳送控制項
	 * @param pc 執行的人物
	 * @param loc 座標
	 * @param head 面向
	 * @param effectable 是否產生動畫
	 * @param skillType 動畫的光 (0:白),(1:青),(2:赤),(3:緑)
	 */
	public static void teleport(final L1PcInstance pc, final L1Location loc, final int head,final boolean effectable, final int skillType) {
		teleport(pc, loc.getX(), loc.getY(), (short) loc.getMapId(), head,effectable, skillType);
	}
	/*
	 * targetキャラクターのdistanceで指定したマス分前にテレポートする。指定されたマスがマップでない場合何もしない。
	 */
	public static void teleportToTargetFront(final L1Character cha,final L1Character target, final int distance) {
		int locX = target.getX();
		int locY = target.getY();
		final int heading = target.getHeading();
		final L1Map map = target.getMap();
		final short mapId = target.getMapId();

		// ターゲットの向きからテレポート先の座標を決める。
		switch (heading) {
		case 1:
			locX += distance;
			locY -= distance;
			break;

		case 2:
			locX += distance;
			break;

		case 3:
			locX += distance;
			locY += distance;
			break;

		case 4:
			locY += distance;
			break;

		case 5:
			locX -= distance;
			locY += distance;
			break;

		case 6:
			locX -= distance;
			break;

		case 7:
			locX -= distance;
			locY -= distance;
			break;

		case 0:
			locY -= distance;
			break;

		default:
			break;

		}

		if (map.isPassable(locX, locY)) {
			if (cha instanceof L1PcInstance) {
				teleportByMagic((L1PcInstance) cha, locX, locY, mapId,cha.getHeading(), true);
			} else if (cha instanceof L1NpcInstance) {
				((L1NpcInstance) cha).teleport(locX, locY, cha.getHeading());
			}
		}
	}
}
